import {Buffer} from "buffer";
import {ReverseByteArrayInputStream} from "./ReverseByteArrayInputStream";


export class DataUtils {

    static hexArray : string[] = ['0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'];

    static readFully(input : ReverseByteArrayInputStream, buffer : Buffer, off : number, len : number) {
        do {
            let bytesRead = input.readoffset(buffer, off, len);
            if (bytesRead == -1) {
                throw new Error("Unexpected end of input stream.");
            }
            len -= bytesRead;
            off += bytesRead;
        } while (len > 0)
    }

    static toBytes(value: string): Buffer {
        if (value == null || value.trim().length <= 0) {
            throw new Error("value is null or value.length = 0");
        }
        value = value.trim();
        if (value.length % 2 != 0) {
            throw new Error("value.length % 2 != 0");
        }
        let ret = Buffer.alloc(value.length / 2);
        for (let i = 0; i < ret.length; i++) {
            try {
                let tmp = value.substring(i * 2, i * 2 + 2);
                ret[i] = parseInt(tmp, 16) & 0xFF;
            } catch (e) {
                throw new Error("cast exception");
            }
        }
        return ret;
    }

    static hexToBytes(hex: string): Buffer {
        if (hex.length < 1) {
            throw new Error("hex is null or empty");
        } else {
            let result = Buffer.alloc(hex.length / 2);
            let j = 0;
            for (let i = 0; i < hex.length; i += 2) {
                // console.log("hexToBytes " + parseInt(hex.substring(i, i + 2), 16));
                result[j++] = parseInt(hex.substring(i, i + 2), 16);
            }
            return result;
        }
    }

    static intToHexString(value : number, bytesLength : number){
        if (bytesLength != 1 && bytesLength != 2 && bytesLength != 4) {
            return null;
        }
        let mask = 0;
        switch (bytesLength) {
            case 1:
                mask = 0x000000FF;
                break;
            case 2:
                mask = 0x0000FFFF;
                break;
            case 4:
                mask = 0xFFFFFFFF;
                break;
        }
        let length = 2 * bytesLength;
        let ret = (value & mask).toString(16);
        let sb = "";
        for (let i = 0; i < (length - ret.length); i++) {
            sb += "0";
        }
        sb += ret;
        return sb.toString();
    }

    static bytesToHexString(buf: Buffer, offset : number, length : number){
        if (buf == null || offset < 0 || length < 0 || offset + length > buf.length) {
            return null;
        }

        let retBuffer = "";

        for (let i = offset; i < offset + length; i++) {
            retBuffer += this.bytetoHexToString(buf[i]);
        }

        return retBuffer.toString().toUpperCase();
    }

    static bytetoHexToString(value: number) : string{
        let tmp = (value & 0xFF).toString(16);
        tmp.toUpperCase();
        return tmp.length % 2 == 1 ? "0" + tmp : tmp;
    }

    static toHexString(buf: Buffer, bytesLength: number, length: number): string {
        if ((bytesLength != 1) && (bytesLength != 2) && (bytesLength != 4)) {
            throw new Error("bytesLength not 1，2，4");
        }
        let sb = "";
        for (let i = length; i < buf.length; i++) {
            let mask = 0;
            switch (bytesLength) {
                case 1:
                    mask = 255;
                    break;
                case 2:
                    mask = 65535;
                    break;
                case 4:
                    mask = -1;
            }
            let length = 2 * bytesLength;
            let b = buf[i] & mask;
            let ret = b.toString(16);
            for (let i = 0; i < length - ret.length; i++) {
                sb += "0";
            }
            sb += ret;
        }
        return sb.toString().toUpperCase();
    }

    static digit(codePoint: number, radix: number): number {
        if (radix < 2 || radix > 36) {
            return -1;
        }
        if (codePoint < 128) {
            // Optimized for ASCII
            let result = -1;
            if ('0'.charCodeAt(0) <= codePoint && codePoint <= '9'.charCodeAt(0)) {
                result = codePoint - '0'.charCodeAt(0);
            } else if ('a'.charCodeAt(0) <= codePoint && codePoint <= 'z'.charCodeAt(0)) {
                result = 10 + (codePoint - 'a'.charCodeAt(0));
            } else if ('A'.charCodeAt(0) <= codePoint && codePoint <= 'Z'.charCodeAt(0)) {
                result = 10 + (codePoint - 'A'.charCodeAt(0));
            }
            return result < radix ? result : -1;
        }
        return -1;
    }

    static toShortHexString(bytes : Buffer, offset : number, length : number, revert : boolean) : string{
        let hexChars = [];
        for (let j = offset; j < offset + length; j++) {
            let v = bytes[j] & 0xFF;
            if (revert) {
                hexChars[(length * 2 - (j - offset) * 2 - 2)] = this.hexArray[(v >>> 4)];
                hexChars[(length * 2 - (j - offset) * 2 - 1)] = this.hexArray[(v & 0xF)];
            } else {
                hexChars[((j - offset) * 2)] = this.hexArray[(v >>> 4)];
                hexChars[((j - offset) * 2 + 1)] = this.hexArray[(v & 0xF)];
            }
        }
        return String(hexChars.join(""));
    }

    static fromShortHexString(str: string, revert: boolean) {
        if (str == null) {
            throw new Error("string s may not be null");
        }
        str.trim();
        str.replace(" ", "");
        if ((str.length == 0) || ((str.length % 2) != 0)) {
            throw new Error("string is not a legal hex string.");
        }
        let length = str.length;
        let data = Buffer.alloc(length / 2);
        for (let i = 0; i < length; i += 2) {
            let firstCharacter = DataUtils.digit(str.charAt(0).charCodeAt(0), 16);
            let secondCharacter = DataUtils.digit(str.charAt(i + 1).charCodeAt(0), 16);
            if ((firstCharacter == -1) || (secondCharacter == -1)) {
                throw new Error("string is not a legal hex string.");
            }
            if (revert) {
                data[((length - i) / 2 - 1)] = (((firstCharacter << 4) + secondCharacter));
            } else {
                data[(i / 2)] = (((firstCharacter << 4) + secondCharacter));
            }
        }
        return data;
    }

}

console.log(DataUtils.intToHexString(0, 1));

